/*
 * Ray
 *
 */

#include "Ray.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>


/*
 *---------------------------------------------------------------------------------------------------------------
 */

int normalizeVector(float * e)
{
        float magnitude = sqrtf(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);

        e[0] /= magnitude;
        e[1] /= magnitude;
        e[2] /= magnitude;

        return 0;
}

int crossR(float *  vector1, float * vector2, float * result)
{
        //calculate the i,j,k coefficients of the cross product 
        float x = vector1[1]*vector2[2]-vector2[1]*vector1[2];
        float y = vector1[0]*vector2[2]-vector2[0]*vector1[2];
        float z = vector1[0]*vector2[1]-vector2[0]*vector1[1];
        result[0] = x;
        result[1] = y;
        result[2] = z;

        return 0;
}

/*
 *---------------------------------------------------------------------------------------------------------------
 */


/*
typedef struct
{
        float *	startPoint;
        float *	direction;
} Ray_t;
*/

/*
 * Crear rayo en las sistema de coordenadas de la cámara
 */
int CreateRay(Ray_t * ray, Camera_t * camera, Screen_t * screen, int x, int y)
{
	ray->startPoint		= (float*) malloc(3*sizeof(float));
	ray->direction		= (float*) malloc(3*sizeof(float));

	ray->startPoint[0] 	= camera->position[0];
	ray->startPoint[1] 	= camera->position[1];
	ray->startPoint[2] 	= camera->position[2];

#if 0
	float ph[3];
	float pw[3];

	ph[0]	= screen->distance * (camera->look[0] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[0]));
	ph[1]	= screen->distance * (camera->look[1] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[1]));
	ph[2]	= screen->distance * (camera->look[2] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[2]));

	pw[0]	= screen->distance * (camera->look[0] +  (tan(screen->fov_W*(M_PI/180.0)) * camera->right[0]));
	pw[1]	= screen->distance * (camera->look[1] +  (tan(screen->fov_W*(M_PI/180.0)) * camera->right[1]));
	pw[2]	= screen->distance * (camera->look[2] +  (tan(screen->fov_W*(M_PI/180.0)) * camera->right[2]));

	ray->direction[0] 	= (((x+0.5)/screen->h)  * ph[0]) + (((y+0.5)/screen->w) * pw[0]); 
        ray->direction[1] 	= (((x+0.5)/screen->h)  * ph[1]) + (((y+0.5)/screen->w) * pw[1]); 
        ray->direction[2] 	= (((x+0.5)/screen->h)  * ph[2]) + (((y+0.5)/screen->w) * pw[2]); 
	ray->direction[0] 	= (((x+0.5)/screen->h)  * ph[0]) ; 
        ray->direction[1] 	= (((x+0.5)/screen->h)  * ph[1]) ; 
        ray->direction[2] 	= (((x+0.5)/screen->h)  * ph[2]) ; 

	//ray->direction[0] 	+= 
	//ray->direction[1] 	+=
	//ray->direction[2] 	+=	

//	normalizeVector(ray->direction);
	
	fprintf(stdout, "(%d,%d) (%f,%f,%f) (%f,%f,%f) \n", x,y,ray->startPoint[0],ray->startPoint[1],ray->startPoint[2],ray->direction[0],ray->direction[1],ray->direction[2]);
#endif

#if 0
	ray->direction[0] 	= (x/(float)screen->H) * screen->distance* (camera->look[0] + tan(screen->fov_H*(M_PI/180.0))*camera->up[0]);
        ray->direction[1] 	= (x/(float)screen->H) * screen->distance* (camera->look[1] + tan(screen->fov_H*(M_PI/180.0))*camera->up[1]);
        ray->direction[2] 	= (x/(float)screen->H) * screen->distance* (camera->look[2] + tan(screen->fov_H*(M_PI/180.0))*camera->up[2]);
	ray->direction[0] 	+= (y/(float)screen->W) * screen->distance* (camera->look[0] + tan(screen->fov_W*(M_PI/180.0))*camera->right[0]);
        ray->direction[1] 	+= (y/(float)screen->W) * screen->distance* (camera->look[1] + tan(screen->fov_W*(M_PI/180.0))*camera->right[1]);
        ray->direction[2] 	+= (y/(float)screen->W) * screen->distance* (camera->look[2] + tan(screen->fov_W*(M_PI/180.0))*camera->right[2]);
//	ray->direction[0] 	+= ray->startPoint[0];
//	ray->direction[1] 	+= ray->startPoint[1];
//	ray->direction[2] 	+= ray->startPoint[2];
	fprintf(stdout, "(%d,%d) (%f,%f,%f) (%f,%f,%f) \n", x,y,ray->startPoint[0],ray->startPoint[1],ray->startPoint[2],ray->direction[0],ray->direction[1],ray->direction[2]);
//	normalizeVector(ray->direction);
//	fprintf(stdout, "(%f,%f,%f) (%f,%f,%f) \n", ray->startPoint[0],ray->startPoint[1],ray->startPoint[2],ray->direction[0],ray->direction[1],ray->direction[2]);
#endif

float ph[3];
float pw[3];

ph[0] = screen->distance * (camera->look[0] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[0]));
ph[1] = screen->distance * (camera->look[1] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[1]));
ph[2] = screen->distance * (camera->look[2] + (tan(screen->fov_H*(M_PI/180.0)) * camera->up[2]));
pw[0] = screen->distance * (camera->look[0] + (tan(screen->fov_W*(M_PI/180.0)) * camera->right[0]));
pw[1] = screen->distance * (camera->look[1] + (tan(screen->fov_W*(M_PI/180.0)) * camera->right[1]));
pw[2] = screen->distance * (camera->look[2] + (tan(screen->fov_W*(M_PI/180.0)) * camera->right[2]));
fprintf(stdout, "(%f,%f,%f) (%f,%f,%f) \n",ph[0],ph[1],ph[2],pw[0],pw[1],pw[2]);
exit(-1);


#if 0

	/*
	 * Vector dirección será direction - origen
	 */
	float cH 		= x*(screen->h/screen->H);
	float cW 		= y*(screen->w/screen->W); 
	crossR(camera->look,camera->up,camera->right);
	ray->direction[0] 	= (screen->distance*camera->look[0]) + cH*camera->up[0] + cW*camera->right[0];
	ray->direction[1] 	= (screen->distance*camera->look[1]) + cH*camera->up[1] + cW*camera->right[1];
	ray->direction[2] 	= (screen->distance*camera->look[2]) + cH*camera->up[2] + cW*camera->right[2];
	normalizeVector(ray->direction);
	fprintf(stdout, "(%d,%d) (%f,%f,%f) (%f,%f,%f) \n", x,y,ray->startPoint[0],ray->startPoint[1],ray->startPoint[2],ray->direction[0],ray->direction[1],ray->direction[2]);
#endif	
#if 0
	float E[3];
	float A[3];
	float w[3];
	float u[3];
	float v[3];
	float P[3];

	float cu = ((2.0*x+1.0)/(2.0*screen->w) - 0.5)*screen->W;
	float cv = ((2.0*y+1.0)/(2.0*screen->h) - 0.5)*screen->H;

	E[0] 	= camera->position[0];	
	E[1] 	= camera->position[1];
        E[2]	= camera->position[2];

	/* XXX
	 * Mal porque suponiedo vector look es 0,0,-1 */
	A[0] 	= camera->position[0] + camera->look[0] * screen->distance;	
	A[1] 	= camera->position[1] + camera->look[1] * screen->distance;
        A[2]	= camera->position[2] + camera->look[2] * screen->distance;

	w[0]	= E[0] - A[0];
	w[1]	= E[1] - A[1];
	w[2]	= E[2] - A[2];
	normalizeVector((float*)w);
	
	crossR(camera->up,(float*)w,(float*)u);
	normalizeVector((float*)u);

	crossR((float*)w,(float*)u,(float*)v);

	P[0]	= A[0] + cu*u[0] + cv*v[0];
	P[1]	= A[1] + cu*u[1] + cv*v[1];
	P[2]	= A[2] + cu*u[2] + cv*v[2];
	
	ray->direction[0] 	=P[0];//= P[0] - E[0];	
        ray->direction[1] 	=P[1];//= P[1] - E[1];
        ray->direction[2] 	=P[2];//= P[2] - E[2];
	normalizeVector(ray->direction);
	fprintf(stdout, "(%f,%f,%f) (%f,%f,%f) \n", ray->startPoint[0],ray->startPoint[1],ray->startPoint[2],ray->direction[0],ray->direction[1],ray->direction[2]);

#endif	

	
	
	return 0;
	
}

int destroyRay(Ray_t r)
{
	free(r.direction);
	free(r.startPoint);

	return 0;
}
#if 0
Ray_t * CreateRay(float * sP, float * eP)
{

	Ray_t * r 	= (Ray_t *) 	malloc(sizeof(Ray_t));
	r->direction	= (float*)	malloc(3*sizeof(float));
	r->vector	= (float*)	malloc(3*sizeof(float));
	r->startPoint	= (float*)      malloc(3*sizeof(float));
	r->endPoint	= (float*)      malloc(3*sizeof(float));

	r->vector[0]   = (eP[0]-sP[0]);
	r->vector[1]   = (eP[1]-sP[1]);
	r->vector[2]   = (eP[2]-sP[2]);

	// Normalize direction
	float module = sqrt((r->vector[0]*r->vector[0])+(r->vector[1]*r->vector[1])+(r->vector[2]*r->vector[2]));

	r->direction[0] = r->vector[0]/module;
	r->direction[1] = r->vector[1]/module;
	r->direction[2] = r->vector[2]/module;
	
	int i = 0;

	for(i=0; i<3; i++)
	{
		r->startPoint[i]= sP[i];
		r->endPoint[i]	= eP[i];
	}

	return r;
}
#endif
